﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.ComponentModel.DataAnnotations;

namespace MiniScrum.Models
{
    public class User : IPrincipal
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "Please enter a username. ")]
        public string UserName { get; set; }
        [Required(ErrorMessage = "Please enter the name. ")]
        public string FullName { get; set; }
        [Required(ErrorMessage = "Please enter a password. ")]
        public string Password { get; set; }
        [RegularExpression(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "Please enter a valid email. ")]
        public string Email { get; set; }
        public virtual ICollection<Role> Roles { get; set; }
        public virtual ICollection<Task> Tasks { get; set; }
        public virtual ICollection<Blocker> Blockers { get; set; }
        public Team Team { get; set; }

        public User()
        {
            Roles = new HashSet<Role>();
            Tasks = new HashSet<Task>();
            Blockers = new HashSet<Blocker>();
        }

        public static User GetUser(string userName, string password)
        {
            using (var db = new MiniScrumDB())
            {
                return db.Users.Where(u => u.UserName == userName && u.Password == password).SingleOrDefault();
            }
        }

        public IIdentity Identity
        {

            get
            {
                bool isAuthenticated = this.IsInRole("admin") | this.IsInRole("teammember");
                return new Identity(isAuthenticated, this.UserName);
            }
        }

        public bool IsInRole(string role)
        {
            return User.IsInRole(this.Id, role);
        }

        public static bool IsInRole(int userId, string role)
        {
            using (MiniScrumDB db = new MiniScrumDB())
            {
                User user = User.GetById(userId);
                db.Users.Attach(user);
                return user.Roles.Where(r => r.RoleName.ToLowerInvariant() == role.ToLowerInvariant()).Count() > 0;
            }
        }

        public static User GetUserByName(string userName)
        {
            User user = null;
            using (MiniScrumDB db = new MiniScrumDB())
            {
                user = db.Users.Where(u => u.UserName == userName).SingleOrDefault();
            }

            return user;

        }

        public static User GetById(int userId)
        {
            using (var db = new MiniScrumDB())
            {
                return db.Users.Include("Roles").Where(u => u.Id == userId).SingleOrDefault();
            }

        }

        public static void Update(User user)
        {
            using (var db = new MiniScrumDB())
            {
                db.Entry(user).State = System.Data.EntityState.Modified;
                db.SaveChanges();
            }
        }

        public static void Create(User newUser)
        {
            using (var db = new MiniScrumDB())
            {
                User user = User.GetUserByName(newUser.UserName);
                if (user == null)
                    db.Users.Add(newUser);
                else
                    throw new ArgumentException("The username cannot be duplicated. ");
                db.SaveChanges();
            }
        }

        /// <summary>
        /// Get all users except current. 
        /// </summary>
        /// <returns></returns>
        public static IList<User> GetList()
        {
            using (var db = new MiniScrumDB())
            {
                MiniScrum.Models.User user = (System.Threading.Thread.CurrentPrincipal as MiniScrum.Models.User);
                List<User> users = (from u in db.Users
                                    select u).ToList().Where(u => u.UserName != user.UserName).ToList();

                return users;

            }
        }

        internal static void Delete(int id)
        {
            using (var db = new MiniScrumDB())
            {
                User user = db.Users.Where(u => u.Id == id).SingleOrDefault();
                if (user != null)
                    db.Users.Remove(user);

                db.SaveChanges();
            }
        }
    }
}